﻿using System;
using Gp.Core;
using Gp.Scripts.Core;
using Helpers;
using QFramework;
using UnityEngine;
using UnityEngine.InputSystem;

namespace Gp.Input
{
    public enum SelectionInputKey
    {
        Right = 0,
        Left = 1,
        Up = 2,
        Down = 3,
    }


    [AutoLoad]
    public class InputManager : BaseGameManager
    {
        public GameInputActions InputAction { get; private set; }

        protected override void OnInit()
        {
            InputAction = new GameInputActions();
            InputAction.Battle.Enable();
            InputAction.City.Enable();


            // 注册基础按键监听
            // InputMapCode.Exit.KeyAction().started += context => this.SendEvent<ExitArgs>();

            // // 控制台打开时关闭输入
            // QuantumConsole.OnActivate += () => {
            //     InputAction.Battle.Disable();
            //     InputAction.City.Disable();
            // };
            //
            // QuantumConsole.OnDeactivate += () => {
            //     InputAction.Battle.Enable();
            //     InputAction.City.Enable();
            // };
        }


        public Vector2 GetMouseOffsetAmount(Vector2 point)
        {
            return Mouse.current.position.ReadValue() - point;
        }

        public Vector2 MousePosition()
        {
            return Mouse.current.position.ReadValue();
        }


        public Vector3 MouseUIPosition(RectTransform transform)
        {
            var canvas = UICanvasHook.Instance.GetCanvas();
            var camera = canvas.worldCamera;
            Vector3 point = MousePosition();
            // point.z = canvas.transform.localPosition.z;
            //
            var viewportPos = camera.ScreenToViewportPoint(point);
            // var uiPos = transform.parent.InverseTransformPoint(worldPos);
            // var res = new Vector3(uiPos.x, uiPos.y, 0);
            // Debug.Log("view Port :" + viewportPos);

            transform.anchoredPosition = new Vector2(
                (viewportPos.x - .5f) * camera.pixelWidth,
                (viewportPos.y - .5f) * camera.pixelHeight
            );

            return transform.localPosition;
        }

        public static Vector3 WorldToUIPosition(RectTransform rect, Vector3 worldPos)
        {
            var camera = UICanvasHook.Instance.GetCanvas().worldCamera;
            Vector2 screenPos = camera.WorldToScreenPoint(worldPos);
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, screenPos, camera, out var res);
            return new Vector3(res.x, res.y, rect.localPosition.z);
        }


        public bool CurrentUnitInfoSwitched()
        {
            return InputAction.Battle.SwitchCurrentUnitInfoWindow.triggered;
        }
        public Vector2 PlayerMovement()
        {
            return this.InputAction.City.PrimaryMovement.ReadValue<Vector2>();
        }
        public bool CancelButtonDown()
        {
            return InputAction.Battle.CancelSkillCast.triggered;
        }

        public static Mouse CurrentMouse()
        {
            return Mouse.current;
        }

        public bool IsRunning()
        {
            return InputAction.City.Run.IsPressed();
        }


        public bool IsSelectionInputKeyDown(out SelectionInputKey key)
        {
            var inputAction = InputAction.City;
            key = SelectionInputKey.Up;
            if (inputAction.SelectionUp.WasPressedThisFrame())
            {
                key = SelectionInputKey.Up;
                return true;
            }
            else if (inputAction.SelectionLeft.WasPerformedThisFrame())
            {
                key = SelectionInputKey.Left;
                return true;
            }
            else if (inputAction.SelectionRight.WasPressedThisFrame())
            {
                key = SelectionInputKey.Right;
                return true;
            }
            else if (inputAction.SelectionDown.WasPerformedThisFrame())
            {
                key = SelectionInputKey.Down;
                return true;
            }

            return false;
        }


        public bool IsMousePressing(MouseButtonCode key)
        {
            var input = Mouse.current;
            return key switch
            {
                MouseButtonCode.MouseLeftButton => input.leftButton.isPressed,
                MouseButtonCode.MouseRightButton => input.rightButton.isPressed,
                MouseButtonCode.MouseMiddleButton => input.middleButton.isPressed,
                _ => throw new ArgumentOutOfRangeException(nameof(key), key, null)
            };
        }

        public IUnRegister Bind(InputMapCode code, Action<InputAction.CallbackContext> action, InputTriggerType triggerType = InputTriggerType.Started)
        {
            var inputAction = code.KeyAction();
            CustomUnRegister ret;
            switch (triggerType)
            {
                case InputTriggerType.Started:
                    inputAction.started += action;
                    ret = new CustomUnRegister(() => inputAction.started -= action);
                    break;
                case InputTriggerType.Performed:
                    inputAction.performed += action;
                    ret = new CustomUnRegister(() => inputAction.performed -= action);
                    break;
                case InputTriggerType.Canceled:
                    inputAction.canceled += action;
                    ret = new CustomUnRegister(() => inputAction.canceled -= action);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(triggerType), triggerType, null);
            }

            return ret;
        }
        
        public void UnBind(InputMapCode code, Action<InputAction.CallbackContext> action, InputTriggerType triggerType = InputTriggerType.Started)
        {
            var inputAction = code.KeyAction();
            switch (triggerType)
            {
                case InputTriggerType.Started:
                    inputAction.started -= action;
                    break;
                case InputTriggerType.Performed:
                    inputAction.performed -= action;
                    break;
                case InputTriggerType.Canceled:
                    inputAction.canceled -= action;
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(triggerType), triggerType, null);
            }
        }


        public static bool MouseRayHit(out RaycastHit raycastHit)
        {
            raycastHit = new RaycastHit();
            if (!ObjectHelper.MainCamera)
            {
                return false;
            }

            Ray ray = ObjectHelper.MainCamera.ScreenPointToRay(Mouse.current.position.ReadValue());
            return Physics.Raycast(ray, out raycastHit);
        }
    }
}